#ifndef _PARSE_CODE_IMPL
#define _PARSE_CODE_IMPL

#include "Parse_code.h"

/* implement code handle function */

namespace parse_code_loc {
	void write_code_pos(mylib::Buffer &from, std::ostream &out, const parse_code::Code_pos pos, size_t tab_len);
}
// handle action code "add_item()
#include "Algorithm.h"
void parse_code::action_code(mylib::Buffer &from, std::ostream &to, int dfa_num, const Item_code &codes){
	to << "\t\tcase " << dfa_num << " : {\n";
	to << "\t\t\tif( !_child ) {\n";
	to << "\t\t\t\t";			// for user's code
	mylib::skip_ws(from);
	parse_code::Code_pos pos;
	int count=1;				// expect the number of '{'
	bool child_exist=false, err=false;
	bool writen=false;			
	char c;
	while (count && from.get(c)) {
		if( c == '/' ) {		// comment
			char ch;
			if( !from.get(ch) )
				throw Err_copy();
			if( ch == '*' ) {	// /* ... */
				mylib::skip_dou_lines_com(from);			// skip comment
			} else if( ch == '/' ) {			// // newline
				mylib::skip_line_com(from);
			} else {		// /normal char
				to << c;
				to << ch;		// normal character
			}
		} else if( c == '\"' ) {		// "..."
			from.ret();
			std::string str;
			try {
				mylib::get_str(from, str);
			} catch(...) {
				err=true;
			}
			writen=true;
			to << '\"';
			to << str;
			to << '\"';
		} else	{	// other
			if( !isalpha(c) ) {
				if( c == '\n' )		// the end line
					to << "\t\t\t";	// for the next line
				else if( c == '}' ) {
					count--;
					if( !count )	// end?
						break;
				} else if( c == '{' )
					count++;
				to << c;
				writen=true;
				continue;
			}
			writen=true;
			std::string id;
			from.ret();
			mylib::get_id(from, id);
			if( id == "add_item" ) {	// match
				mylib::skip_ws(from);		// skip white space
				if( from.get(c) && c == '(' ) {
					id.clear();
					mylib::get_id(from, id);	// get a code identifier
					mylib::skip_ws(from);
					if( from.get(c) && c == ')' ) {
						mylib::skip_ws(from);
						if( !from.get(c) || c != ';' ) {	// add_item(code_name);
							std::cerr << "add item failed, missing a ';' at the end.\n";
							err=true;
							continue;
						}
						Item_code::const_iterator C;
						if( (C=codes.find(id)) != codes.end() ) {	//exist
							to << "\t\t\t\ttry {\n";
							to << "Dfa *dfa=0;\n";
							to << "\t\t\t\t\tdfa=new Dfa(_str.c_str(), " << -dfa_num << " , _start_line);\n";
							to << "\t\t\t\t\t_dfa_set.push_back(dfa);\n";	// add new item
							to << "\t\t\t\t}catch(...) {\n";
							to << "\t\t\t\t\tthrow Out_of_mem();\n";
							to << "\t\t\t\t}\n";
							mylib::skip_ws(from);			// delete '\n'
							to << "\t\t\t\t";
							pos = C->second;
							child_exist=true;
						} else {
							std::cerr << "Undefined new item code.\n";
							err=true;
						}
					} else if( from.eof() )
						throw Err_copy();
					else {	// c != ')'
						std::cerr << "add item failed, since it doesn't match syntax grammer.\n";
						err=true;
					}
				} else if( from.eof() )
					throw Err_copy();
				else 		// c != '('
					err=true;
			} else		// not add item
				to << id;
		}
	}
	to << ((writen) ? "\t\t\t}" : ";\n\t\t\t}");
	if( c != '}' || err )
		throw Err_copy();
	if( child_exist ) {
		to << " else {\n";			// write child's code
		int buf_pos = from.tellg();
		parse_code_loc::write_code_pos(from, to, pos, 4);
		from.seekg(buf_pos-1);			// return the '}' character
		to << "\t\t\t}\n";
		to << "\t\t\tbreak;\t}\n";
		return ;
	} else {
		from.ret();		// return '}'
		to << "\n\t\t\tbreak;\t}\n";
	}
}	
parse_code::Code_pos parse_code::item_code(mylib::Buffer &from){			// handle new item's code
	Code_pos pos;
	mylib::skip_ws(from);
	pos.start = from.tellg();		// get the start position
	bool err=false;
	int count=1;
	char c;
	while ( count && from.get(c) ) {
		if( c == '/' ) {		// comment
			char ch;
			if( !from.get(ch) )
				throw Err_copy();
			if( ch == '*' ) {	// /* ... */
				mylib::skip_dou_lines_com(from);
			} else if( ch == '/' ) {			// // newline
				mylib::skip_line_com(from);
			}
		} else if( c == '\"' ) {		// "..."
			std::string str;
			from.ret();				// return '\"'
			try {
				mylib::get_str(from, str);
			} catch(...) {
				err = true;
			}
		} else if( c == '{' )
			count++;
		else if( c== '}' )
			count--;
	}
	if( c != '}' || err )
		throw Err_copy();
	from.ret();			// return '}'
	pos.end = from.tellg()-1;
	return pos;
}
#include <fstream>
// copy code to match the end sign
void parse_code::copycode(mylib::Buffer &from, std::ostream &to, const char *end_sign) {
	char c;
	bool err=false;
	if( !end_sign )	{			// copy to the end
		while( from.get(c) )
			to << c;
		return;
	}
	while( from.get(c) ) {
		if( c == *end_sign ) {		// is end sign
			char ch;
			int i=1;
			while( end_sign[i] ){	// matched ?
				if( !from.get(ch) )
					throw parse_code::Err_copy();
				else if( ch != end_sign[i] ) {		// unmatched
					from.ret(i);		//unget
					break;
				} else 	// test next
					i++;
			}
			if( !end_sign[i] )	{ // matched
				from.ret(i);
				return;
			}
		}
		if( c == '/' ) {		// comment
			char ch;
			if( !from.get(ch) )
				throw Err_copy();
			if( ch == '*' ) {	// /* ... */
				mylib::skip_dou_lines_com(from);
			} else if( ch == '/' ) {			// // newline
				mylib::skip_line_com(from);
			} else {		// /normal char
				to << c;
				to << ch;		// normal character
			}
		} else if( c == '\"' ) {		// "..."
			from.ret();
			std::string str;
			try {
				mylib::get_str(from, str);
			} catch(...) {
				err=true;
			}
			to << '\"';
			to << str;
			to << '\"';
		} else		// other
			to << c;
	}
	to << std::endl;
	if( err )
		throw Err_copy();
}
namespace write_code_loc {
	void write_init(std::ostream &out, int dfa_num);
	void copy_left_code(std::istream &in, std::ostream &out);
}
#include <fstream>
void parse_code::write_static_code(std::ostream &out){
	using namespace write_code_loc;
	out << "/* static code in here */ " << std::endl;
	try {
		const char _left_code_file[] = "c:\\dlex\\code\\left_code.cpp";
		std::ifstream left_code_file(_left_code_file);
		if( !left_code_file )
			throw parse_code::Err_copy();
		copy_left_code(left_code_file, out);
	} catch(...) {
		throw parse_code::Err_copy();
	}
}
void parse_code::write_data_init(std::istream &in, std::ostream &out,int dfa_num){	// write data
	out << "namespace dlex_loc_data {\n";
	write_code_loc::copy_left_code(in, out);
	out << "}\n";
	write_code_loc::write_init(out, dfa_num);
}
void write_code_loc::write_init(std::ostream &out, int dfa_num) {
	out << "void dlex_loc::init(std::list<Dfa *> &dfa_set) {\n";
	out << "\tusing namespace dlex_loc_data;\n";
	if( dfa_num )
		out << "\tDfa *dfa;\n";
	out << "\ttry {\n";

	while( dfa_num > 0 ) {
		out << "\t\tdfa = new Dfa(" << "dfa" << dfa_num << ",true);\n";
		out << "\t\tdfa_set.push_back(dfa);\n";
		dfa_num--;
	}
	out << "\t} catch(std::bad_alloc) {\n";
	out << "\t\tthrow dlex::Dlex::Out_of_mem();\n";
	out << "\t}";
	out << " catch(...) {\n";
	out << "\t\tthrow dlex::Dlex::Err_input();\n";
	out << "\t}\n}\n";
}
void write_code_loc::copy_left_code(std::istream &in, std::ostream &out) {
	char c;
	while( in.get(c) )
		out << c;
}
void parse_code::write_next_token(mylib::Buffer &from, std::ostream &out, std::string &ret_type,Code_pos *usr_data) {
	out << ret_type << ' ';				// output return type
	out << "dlex::Dlex::next_token() {\n";
	out << "\tusing namespace std;\n";
	out << "\tbool _child;\n";
	if( usr_data ) {		// write user data
		int buf_pos = from.tellg();
		parse_code_loc::write_code_pos(from, out, *usr_data, 1);
		from.seekg(buf_pos);			// return the '}' character
	} else
		out << '\t';
	out << "for(; ; ) {\n";
	out << "\t\tint _dfa_num=dlex::Dlex::_get_match_dfa();\n";
	out << "\t\tif( _dfa_num < 0 ) {\n";
	out << "\t\t\t_child=true;\n";
	out << "\t\t\t_dfa_num = -_dfa_num;\n";
	out << "\t\t} else\n";
	out << "\t\t\t_child=false;\n";
	out << "\t\tswitch(_dfa_num) {\n";
}
void parse_code::write_next_token_left(mylib::Buffer &from, std::ostream &out, Code_pos *end_code) {
	out << "\t\tcase dlex_loc::End : {\n";
	if( !end_code )						// if it doesn't exist end code
		out << "\t\t\treturn 0;\t\t}\n";
	else {							// output the end code
		int buf_pos = from.tellg();
		parse_code_loc::write_code_pos(from, out, *end_code, 3);
		from.seekg(buf_pos);			// return the '}' character
		out << "\t\t}\n";
	}
	out << "\t\tdefault : \n";
	out << "\t\t\t_out << _str;\n";
	out << "\t\t\tbreak;\n";
	out << "\t\t}\n";		// for the switch
	out << "\t}\n";			// for the for loop
	if( !end_code )				// there is not end code
		out << "\treturn 0;\n";		// return -1 for the end
	out << "}\n";
}
parse_code::Code_pos parse_code::get_usr_data_pos(mylib::Buffer &from){	// get user data definition position, if exist
	Code_pos pos;
	pos.start = pos.end = 0;
	char c;
	while( from.get(c) ) {		// go to next line
		if( c == '\n' )
			break;
		else if( !isspace(c) ) {
			from.ret();
			return pos;
		}
	}
test:
	if( from.get(c) ) {		// to determine whether there exists data definition or not
		if( !isspace(c) ) {
			from.ret();
			return pos;
		} else {
			bool exist=false;
			while( !exist ) {
				if( from.get(c) ) {
					if( c == '\n' )		// continue test
						goto test;
					else if( !isspace(c) ) {		// exist user data
						exist=true;
						from.ret();
					}
				} else			// the end
					return pos;
			}
		}
	} else		// the end file
		return pos;
	bool end=false;
	pos.start = from.tellg();	// get the start position
	while(!end && from.get(c)) {
		if( c == '\n' ) {
			if( from.get(c) ) {
				if( !isspace(c) ) {
					from.ret();		// the end
					end=true;
				}
			} else {		// the end of file
				end=true;
			}
		}
	}
	pos.end = from.tellg()-1;
	return pos;
}			
parse_code::Code_pos parse_code::get_end_code_pos(mylib::Buffer &from){		// get end code position
	// skip the {
	mylib::skip_ws(from);
	char c;
	if( from.get(c) && c =='{')		// get start
		;
	else {
		if( !from.eof() )
			from.ret();
		throw Err_copy();
	}
	Code_pos pos=item_code(from);		// they have the same operation
	from.get(c);				// eat '}'
	return pos;
}
void parse_code_loc::write_code_pos(mylib::Buffer &from,std::ostream &out,const parse_code::Code_pos pos,size_t tab_len) {
	int start = pos.start;
	int code_len = pos.end-start;
	from.seekg(start);		// set to code start
	char ch;
	if( code_len <= 0 ) {
		size_t space_len=tab_len;
		while( space_len-- > 0 )
			out << "\t";
		out << ',';
		out << std::endl;
	} else {
		size_t space_len=tab_len;
		while( space_len-- > 0 )
			out << "\t";
		while( code_len-- > 0 && from.get(ch)) {
			out << ch;
			if( ch == '\n' )	{	// not the last one
				if( code_len > 0 ) {
					size_t space_len=tab_len+1;
					while( space_len-- > 0 )
						out << "\t";
				} else {
					size_t space_len=tab_len;
					while( space_len-- > 0 )
						out << "\t";
				}
			}
		}
	}
	if( code_len >= 0 )
		throw parse_code::Err_copy();
}
#endif
